
const degToRad = (deg) => {
  return deg * Math.PI / 180;
};

const values = (obj) => {
  const array = [];
  for (const key in obj) {
    array.push(obj[key]);
  }
  return array;
};

exports.processPoints = (firstPoint, secondPoint, thirdPoint, sessionPoints, width, height, radius) => {
  const initialPoints = [firstPoint, secondPoint, thirdPoint];
  let transformedPoints = sessionPoints.concat(initialPoints);

  /*
   * Traslate all points moving the secondPoint to (0, 0) on the plane
   */
  transformedPoints = transformedPoints.map((p) => {
    return {
      x: p.x - secondPoint.x,
      y: p.y - secondPoint.y
    };
  });

  /*
   * Get rotation angle
   */
  const y = thirdPoint.y - secondPoint.y;
  const x = thirdPoint.x - secondPoint.x;
  const angle = 2 * Math.PI - Math.atan2(y, x);

  /*
   * Rotate to make field parallel to x axis
   * https://en.wikipedia.org/wiki/Rotation_matrix
   */
  const cos = Math.cos(angle);
  const sin = Math.sin(angle);
  transformedPoints = transformedPoints.map((p) => {
    return {
      x: p.x * cos - p.y * sin,
      y: p.x * sin + p.y * cos
    };
  });

  const transformedFirstPoint = transformedPoints[transformedPoints.length - 3];
  const transformedSecondPoint = transformedPoints[transformedPoints.length - 2];
  const transformedThirdPoint = transformedPoints[transformedPoints.length - 1];
  const transformedInitialPoints = [transformedFirstPoint, transformedSecondPoint, transformedThirdPoint];

  /*
   * Fixing cases when rectangle is in any negative coordinates
   */
  const xMin = Math.min(...transformedInitialPoints.map((p) => p.x));
  const yMin = Math.min(...transformedInitialPoints.map((p) => p.y));
  transformedPoints.forEach((p) => {
    p.x -= Math.floor(xMin < 0 ? xMin : 0);
    p.y -= Math.floor(yMin < 0 ? yMin : 0);
  });

   /*
   * Adding heat parameter
   */
  const heatPoints = {};
  transformedPoints.forEach((p) => {
    const pointString = `${p.x}-${p.y}`;
    heatPoints[pointString] = {
      ...p,
      value: ((heatPoints[pointString] && heatPoints[pointString].value) || 0) + 1
    };
  });
  transformedPoints = values(heatPoints);

  /*
   * Scaling to screen
   */
  const xMax = Math.max(...transformedInitialPoints.map((p) => p.x));
  const yMax = Math.max(...transformedInitialPoints.map((p) => p.y));
  transformedPoints.forEach((p) => {
    p.x = Math.floor(p.x * (width - 3 * radius) / xMax + radius);
    p.y = Math.floor(p.y * (height - 3 * radius) / yMax + radius);
  });

  /*
   * Filtering outside points
  */
  const scaledXMax = xMax * (width - 3 * radius) / xMax + radius;
  const scaledYMax = yMax * (height - 3 * radius) / yMax + radius;
  transformedPoints = transformedPoints.filter((p) => {
    return p.x >= -radius && p.x <= scaledXMax + radius &&
           p.y >= -radius && p.y <= scaledYMax + radius;
  });

  // TODO: remove initial points
  return transformedPoints;
};

/**
 * 生成插值点
 * model:1=>横坐标等间距;2=>两点间距离等分
 */
exports.generatePoints = (points, radius = 1, model = 1) => {
    let length = points.length;
    let newPoints = [];

    for (let index = 0; index < length; index++) {
        newPoints[index] = points[index];
    }

    for (let i = 1; i < length - 1; i++) {
        for (let j = i + 1; j < length; j++) {
            let x1 = points[i].x;
            let y1 = points[i].y;
            let value1 = points[i].value;
            let x2 = points[j].x;
            let y2 = points[j].y;
            let value2 = points[j].value;

            switch(model) {
                case 1:
                   // (x-x1)/(x2-x1)=(y-y1)/(y2-y1)=> y = (x - x1) * (y2 - y1) / (x2 - x1)
                  if (x1 - x2 == 0) {
                    let sign = points[i].y - points[j].y > 0 ? -1 : 1;
                    let segValue = (points[i].value - points[j].value) / (points[i].y - points[j].y);

                    for (let temp = y1, count = 1; temp < y2; temp = temp + sign, count++) {
                      newPoints.push({x: x1, y: temp, value: points[i].value + segValue * count});
                    }
                    
                  } else {
                    let sign = points[i].x - points[j].x > 0 ? -1 : 1;
                    let segValue = (points[i].value - points[j].value) / (points[i].x - points[j].x);

                    for (let temp = x1, count = 1; temp != x2; temp = temp + sign, count++) {
                        //  console.log(temp + ";" + x2 + ";" + segValue + ";" + sign);
                      let tempY = (temp - x1) * (y2 - y1) / (x2 - x1) + y1;
                      newPoints.push({x: temp, y: parseInt(tempY), value: points[i].value + segValue * count});
                    }
                  }break;

                  case 2:
                    let totalLength = Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)) ;
                    let totalSeg = parseInt(totalLength/ radius) + 1;
                    let segValue = (value2 - value1) / totalSeg;
                    for (let count = 1; count < totalSeg; count ++) {
                        let tempX = x1 + count * radius * (x2 - x1) / totalLength;
                        let tempY = (tempX - x1) * (y2 - y1) / (x2 - x1) + y1;
                        let tempValue = parseFloat(points[i].value) + parseFloat(segValue * count);
                        newPoints.push({x: tempX, y: parseInt(tempY), value: tempValue});
                    }
                  break;
            }
        }
      
    }

    return newPoints;
}